home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-03 | 80.6 KB | 3,198 lines |
- Newsgroups: comp.sources.unix
- From: pmiller@bmr.gov.au (Peter Miller)
- Subject: v26i216: cook-1.4 - a file construction tool (like "make"), Part08/11
- Sender: unix-sources-moderator@efficacy.home.vix.com
- Approved: WhoAmI@efficacy.home.vix.com
-
- Submitted-By: pmiller@bmr.gov.au (Peter Miller)
- Posting-Number: Volume 26, Issue 216
- Archive-Name: cook-1.4/part08
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 8 (of 11)."
- # Contents: LICENSE common/str.c cook/main.c doc/language
- # Wrapped by vixie@efficacy.home.vix.com on Tue May 4 01:36:41 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'LICENSE' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'LICENSE'\"
- else
- echo shar: Extracting \"'LICENSE'\" \(17982 characters\)
- sed "s/^X//" >'LICENSE' <<'END_OF_FILE'
- X GNU GENERAL PUBLIC LICENSE
- X Version 2, June 1991
- X
- X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- X 675 Mass Ave, Cambridge, MA 02139, USA
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license document, but changing it is not allowed.
- X
- X Preamble
- X
- X The licenses for most software are designed to take away your
- Xfreedom to share and change it. By contrast, the GNU General Public
- XLicense is intended to guarantee your freedom to share and change free
- Xsoftware--to make sure the software is free for all its users. This
- XGeneral Public License applies to most of the Free Software
- XFoundation's software and to any other program whose authors commit to
- Xusing it. (Some other Free Software Foundation software is covered by
- Xthe GNU Library General Public License instead.) You can apply it to
- Xyour programs, too.
- X
- X When we speak of free software, we are referring to freedom, not
- Xprice. Our General Public Licenses are designed to make sure that you
- Xhave the freedom to distribute copies of free software (and charge for
- Xthis service if you wish), that you receive source code or can get it
- Xif you want it, that you can change the software or use pieces of it
- Xin new free programs; and that you know you can do these things.
- X
- X To protect your rights, we need to make restrictions that forbid
- Xanyone to deny you these rights or to ask you to surrender the rights.
- XThese restrictions translate to certain responsibilities for you if you
- Xdistribute copies of the software, or if you modify it.
- X
- X For example, if you distribute copies of such a program, whether
- Xgratis or for a fee, you must give the recipients all the rights that
- Xyou have. You must make sure that they, too, receive or can get the
- Xsource code. And you must show them these terms so they know their
- Xrights.
- X
- X We protect your rights with two steps: (1) copyright the software, and
- X(2) offer you this license which gives you legal permission to copy,
- Xdistribute and/or modify the software.
- X
- X Also, for each author's protection and ours, we want to make certain
- Xthat everyone understands that there is no warranty for this free
- Xsoftware. If the software is modified by someone else and passed on, we
- Xwant its recipients to know that what they have is not the original, so
- Xthat any problems introduced by others will not reflect on the original
- Xauthors' reputations.
- X
- X Finally, any free program is threatened constantly by software
- Xpatents. We wish to avoid the danger that redistributors of a free
- Xprogram will individually obtain patent licenses, in effect making the
- Xprogram proprietary. To prevent this, we have made it clear that any
- Xpatent must be licensed for everyone's free use or not licensed at all.
- X
- X The precise terms and conditions for copying, distribution and
- Xmodification follow.
- X
- X GNU GENERAL PUBLIC LICENSE
- X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- X
- X 0. This License applies to any program or other work which contains
- Xa notice placed by the copyright holder saying it may be distributed
- Xunder the terms of this General Public License. The "Program", below,
- Xrefers to any such program or work, and a "work based on the Program"
- Xmeans either the Program or any derivative work under copyright law:
- Xthat is to say, a work containing the Program or a portion of it,
- Xeither verbatim or with modifications and/or translated into another
- Xlanguage. (Hereinafter, translation is included without limitation in
- Xthe term "modification".) Each licensee is addressed as "you".
- X
- XActivities other than copying, distribution and modification are not
- Xcovered by this License; they are outside its scope. The act of
- Xrunning the Program is not restricted, and the output from the Program
- Xis covered only if its contents constitute a work based on the
- XProgram (independent of having been made by running the Program).
- XWhether that is true depends on what the Program does.
- X
- X 1. You may copy and distribute verbatim copies of the Program's
- Xsource code as you receive it, in any medium, provided that you
- Xconspicuously and appropriately publish on each copy an appropriate
- Xcopyright notice and disclaimer of warranty; keep intact all the
- Xnotices that refer to this License and to the absence of any warranty;
- Xand give any other recipients of the Program a copy of this License
- Xalong with the Program.
- X
- XYou may charge a fee for the physical act of transferring a copy, and
- Xyou may at your option offer warranty protection in exchange for a fee.
- X
- X 2. You may modify your copy or copies of the Program or any portion
- Xof it, thus forming a work based on the Program, and copy and
- Xdistribute such modifications or work under the terms of Section 1
- Xabove, provided that you also meet all of these conditions:
- X
- X a) You must cause the modified files to carry prominent notices
- X stating that you changed the files and the date of any change.
- X
- X b) You must cause any work that you distribute or publish, that in
- X whole or in part contains or is derived from the Program or any
- X part thereof, to be licensed as a whole at no charge to all third
- X parties under the terms of this License.
- X
- X c) If the modified program normally reads commands interactively
- X when run, you must cause it, when started running for such
- X interactive use in the most ordinary way, to print or display an
- X announcement including an appropriate copyright notice and a
- X notice that there is no warranty (or else, saying that you provide
- X a warranty) and that users may redistribute the program under
- X these conditions, and telling the user how to view a copy of this
- X License. (Exception: if the Program itself is interactive but
- X does not normally print such an announcement, your work based on
- X the Program is not required to print an announcement.)
- X
- XThese requirements apply to the modified work as a whole. If
- Xidentifiable sections of that work are not derived from the Program,
- Xand can be reasonably considered independent and separate works in
- Xthemselves, then this License, and its terms, do not apply to those
- Xsections when you distribute them as separate works. But when you
- Xdistribute the same sections as part of a whole which is a work based
- Xon the Program, the distribution of the whole must be on the terms of
- Xthis License, whose permissions for other licensees extend to the
- Xentire whole, and thus to each and every part regardless of who wrote it.
- X
- XThus, it is not the intent of this section to claim rights or contest
- Xyour rights to work written entirely by you; rather, the intent is to
- Xexercise the right to control the distribution of derivative or
- Xcollective works based on the Program.
- X
- XIn addition, mere aggregation of another work not based on the Program
- Xwith the Program (or with a work based on the Program) on a volume of
- Xa storage or distribution medium does not bring the other work under
- Xthe scope of this License.
- X
- X 3. You may copy and distribute the Program (or a work based on it,
- Xunder Section 2) in object code or executable form under the terms of
- XSections 1 and 2 above provided that you also do one of the following:
- X
- X a) Accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of Sections
- X 1 and 2 above on a medium customarily used for software interchange; or,
- X
- X b) Accompany it with a written offer, valid for at least three
- X years, to give any third party, for a charge no more than your
- X cost of physically performing source distribution, a complete
- X machine-readable copy of the corresponding source code, to be
- X distributed under the terms of Sections 1 and 2 above on a medium
- X customarily used for software interchange; or,
- X
- X c) Accompany it with the information you received as to the offer
- X to distribute corresponding source code. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form with such
- X an offer, in accord with Subsection b above.)
- X
- XThe source code for a work means the preferred form of the work for
- Xmaking modifications to it. For an executable work, complete source
- Xcode means all the source code for all modules it contains, plus any
- Xassociated interface definition files, plus the scripts used to
- Xcontrol compilation and installation of the executable. However, as a
- Xspecial exception, the source code distributed need not include
- Xanything that is normally distributed (in either source or binary
- Xform) with the major components (compiler, kernel, and so on) of the
- Xoperating system on which the executable runs, unless that component
- Xitself accompanies the executable.
- X
- XIf distribution of executable or object code is made by offering
- Xaccess to copy from a designated place, then offering equivalent
- Xaccess to copy the source code from the same place counts as
- Xdistribution of the source code, even though third parties are not
- Xcompelled to copy the source along with the object code.
- X
- X 4. You may not copy, modify, sublicense, or distribute the Program
- Xexcept as expressly provided under this License. Any attempt
- Xotherwise to copy, modify, sublicense or distribute the Program is
- Xvoid, and will automatically terminate your rights under this License.
- XHowever, parties who have received copies, or rights, from you under
- Xthis License will not have their licenses terminated so long as such
- Xparties remain in full compliance.
- X
- X 5. You are not required to accept this License, since you have not
- Xsigned it. However, nothing else grants you permission to modify or
- Xdistribute the Program or its derivative works. These actions are
- Xprohibited by law if you do not accept this License. Therefore, by
- Xmodifying or distributing the Program (or any work based on the
- XProgram), you indicate your acceptance of this License to do so, and
- Xall its terms and conditions for copying, distributing or modifying
- Xthe Program or works based on it.
- X
- X 6. Each time you redistribute the Program (or any work based on the
- XProgram), the recipient automatically receives a license from the
- Xoriginal licensor to copy, distribute or modify the Program subject to
- Xthese terms and conditions. You may not impose any further
- Xrestrictions on the recipients' exercise of the rights granted herein.
- XYou are not responsible for enforcing compliance by third parties to
- Xthis License.
- X
- X 7. If, as a consequence of a court judgment or allegation of patent
- Xinfringement or for any other reason (not limited to patent issues),
- Xconditions are imposed on you (whether by court order, agreement or
- Xotherwise) that contradict the conditions of this License, they do not
- Xexcuse you from the conditions of this License. If you cannot
- Xdistribute so as to satisfy simultaneously your obligations under this
- XLicense and any other pertinent obligations, then as a consequence you
- Xmay not distribute the Program at all. For example, if a patent
- Xlicense would not permit royalty-free redistribution of the Program by
- Xall those who receive copies directly or indirectly through you, then
- Xthe only way you could satisfy both it and this License would be to
- Xrefrain entirely from distribution of the Program.
- X
- XIf any portion of this section is held invalid or unenforceable under
- Xany particular circumstance, the balance of the section is intended to
- Xapply and the section as a whole is intended to apply in other
- Xcircumstances.
- X
- XIt is not the purpose of this section to induce you to infringe any
- Xpatents or other property right claims or to contest validity of any
- Xsuch claims; this section has the sole purpose of protecting the
- Xintegrity of the free software distribution system, which is
- Ximplemented by public license practices. Many people have made
- Xgenerous contributions to the wide range of software distributed
- Xthrough that system in reliance on consistent application of that
- Xsystem; it is up to the author/donor to decide if he or she is willing
- Xto distribute software through any other system and a licensee cannot
- Ximpose that choice.
- X
- XThis section is intended to make thoroughly clear what is believed to
- Xbe a consequence of the rest of this License.
- X
- X 8. If the distribution and/or use of the Program is restricted in
- Xcertain countries either by patents or by copyrighted interfaces, the
- Xoriginal copyright holder who places the Program under this License
- Xmay add an explicit geographical distribution limitation excluding
- Xthose countries, so that distribution is permitted only in or among
- Xcountries not thus excluded. In such case, this License incorporates
- Xthe limitation as if written in the body of this License.
- X
- X 9. The Free Software Foundation may publish revised and/or new versions
- Xof the General Public License from time to time. Such new versions will
- Xbe similar in spirit to the present version, but may differ in detail to
- Xaddress new problems or concerns.
- X
- XEach version is given a distinguishing version number. If the Program
- Xspecifies a version number of this License which applies to it and "any
- Xlater version", you have the option of following the terms and conditions
- Xeither of that version or of any later version published by the Free
- XSoftware Foundation. If the Program does not specify a version number of
- Xthis License, you may choose any version ever published by the Free Software
- XFoundation.
- X
- X 10. If you wish to incorporate parts of the Program into other free
- Xprograms whose distribution conditions are different, write to the author
- Xto ask for permission. For software which is copyrighted by the Free
- XSoftware Foundation, write to the Free Software Foundation; we sometimes
- Xmake exceptions for this. Our decision will be guided by the two goals
- Xof preserving the free status of all derivatives of our free software and
- Xof promoting the sharing and reuse of software generally.
- X
- X NO WARRANTY
- X
- X 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- XREPAIR OR CORRECTION.
- X
- X 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- XPOSSIBILITY OF SUCH DAMAGES.
- X
- X END OF TERMS AND CONDITIONS
- X
- X Appendix: How to Apply These Terms to Your New Programs
- X
- X If you develop a new program, and you want it to be of the greatest
- Xpossible use to the public, the best way to achieve this is to make it
- Xfree software which everyone can redistribute and change under these terms.
- X
- X To do so, attach the following notices to the program. It is safest
- Xto attach them to the start of each source file to most effectively
- Xconvey the exclusion of warranty; and each file should have at least
- Xthe "copyright" line and a pointer to where the full notice is found.
- X
- X <one line to give the program's name and a brief idea of what it does.>
- X Copyright (C) 19yy <name of author>
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 2 of the License, or
- X (at your option) any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- XAlso add information on how to contact you by electronic and paper mail.
- X
- XIf the program is interactive, make it output a short notice like this
- Xwhen it starts in an interactive mode:
- X
- X Gnomovision version 69, Copyright (C) 19yy name of author
- X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- X This is free software, and you are welcome to redistribute it
- X under certain conditions; type `show c' for details.
- X
- XThe hypothetical commands `show w' and `show c' should show the appropriate
- Xparts of the General Public License. Of course, the commands you use may
- Xbe called something other than `show w' and `show c'; they could even be
- Xmouse-clicks or menu items--whatever suits your program.
- X
- XYou should also get your employer (if you work as a programmer) or your
- Xschool, if any, to sign a "copyright disclaimer" for the program, if
- Xnecessary. Here is a sample; alter the names:
- X
- X Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- X `Gnomovision' (which makes passes at compilers) written by James Hacker.
- X
- X <signature of Ty Coon>, 1 April 1989
- X Ty Coon, President of Vice
- X
- XThis General Public License does not permit incorporating your program into
- Xproprietary programs. If your program is a subroutine library, you may
- Xconsider it more useful to permit linking proprietary applications with the
- Xlibrary. If this is what you want to do, use the GNU Library General
- XPublic License instead of this License.
- END_OF_FILE
- if test 17982 -ne `wc -c <'LICENSE'`; then
- echo shar: \"'LICENSE'\" unpacked with wrong size!
- fi
- # end of 'LICENSE'
- fi
- if test -f 'common/str.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'common/str.c'\"
- else
- echo shar: Extracting \"'common/str.c'\" \(22749 characters\)
- sed "s/^X//" >'common/str.c' <<'END_OF_FILE'
- X/*
- X * cook - file construction tool
- X * Copyright (C) 1991, 1992, 1993 Peter Miller.
- X * All rights reserved.
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of the GNU General Public License as published by
- X * the Free Software Foundation; either version 2 of the License, or
- X * (at your option) any later version.
- X *
- X * This program is distributed in the hope that it will be useful,
- X * but WITHOUT ANY WARRANTY; without even the implied warranty of
- X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X * GNU General Public License for more details.
- X *
- X * You should have received a copy of the GNU General Public License
- X * along with this program; if not, write to the Free Software
- X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X *
- X * MANIFEST: functions to manipulate shared strings
- X *
- X * Strings are the most heavily used resource in cook. They are manipulated
- X * inside the match functions, and hence are in the inside loop. For this
- X * reason they must be fast.
- X *
- X * A literal pool is maintained. Each string has a reference count. The
- X * string stays in the literal pool for as long as it hash a positive
- X * reference count. To determine if a string is already in the literal pool,
- X * linear dynamic hashing is used to guarantee an O(1) search. That all equal
- X * strings are the same item in the literal pool means that string equality is
- X * a pointer test, and thus very fast.
- X */
- X
- X#include <ctype.h>
- X#include <stddef.h>
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <string.h>
- X
- X#include <error.h>
- X#include <mem.h>
- X#include <s-v-arg.h>
- X#include <str.h>
- X
- X
- X/*
- X * maximum conversion width for numbers
- X */
- X#define MAX_WIDTH 509
- X
- Xstring_ty *str_true;
- Xstring_ty *str_false;
- Xstatic string_ty **hash_table;
- Xstatic str_hash_ty hash_modulus;
- Xstatic str_hash_ty hash_cutover;
- Xstatic str_hash_ty hash_cutover_mask;
- Xstatic str_hash_ty hash_cutover_split_mask;
- Xstatic str_hash_ty hash_split;
- Xstatic str_hash_ty hash_load;
- X
- X#define MAX_HASH_LEN 20
- X
- X
- X/*
- X * NAME
- X * hash_generate - hash string to number
- X *
- X * SYNOPSIS
- X * str_hash_ty hash_generate(char *s, size_t n);
- X *
- X * DESCRIPTION
- X * The hash_generate function is used to make a number from a string.
- X *
- X * RETURNS
- X * str_hash_ty - the magic number
- X *
- X * CAVEAT
- X * Only the last MAX_HASH_LEN characters are used.
- X * It is important that str_hash_ty be unsigned (int or long).
- X */
- X
- Xstatic str_hash_ty hash_generate _((char *, size_t));
- X
- Xstatic str_hash_ty
- Xhash_generate(s, n)
- X char *s;
- X size_t n;
- X{
- X str_hash_ty retval;
- X
- X if (n > MAX_HASH_LEN)
- X {
- X s += n - MAX_HASH_LEN;
- X n = MAX_HASH_LEN;
- X }
- X
- X retval = 0;
- X while (n > 0)
- X {
- X retval = (retval + (retval << 1)) ^ *s++;
- X --n;
- X }
- X return retval;
- X}
- X
- X
- X/*
- X * NAME
- X * str_valid - test a string
- X *
- X * SYNOPSIS
- X * int str_valid(string_ty *s);
- X *
- X * DESCRIPTION
- X * The str_valid function is used to test if a pointer points to a valid
- X * string.
- X *
- X * RETURNS
- X * int: zero if the string is not valid, nonzero if the string is valid.
- X *
- X * CAVEAT
- X * This function is only available then the DEBUG symbol is #define'd.
- X */
- X
- X#ifdef DEBUG
- X
- Xint
- Xstr_valid(s)
- X string_ty *s;
- X{
- X return
- X (
- X s->str_references > 0
- X &&
- X strlen(s->str_text) == s->str_length
- X &&
- X s->str_hash == hash_generate(s->str_text, s->str_length)
- X );
- X}
- X
- X#endif
- X
- X
- X/*
- X * NAME
- X * str_initialize - start up string table
- X *
- X * SYNOPSIS
- X * void str_initialize(void);
- X *
- X * DESCRIPTION
- X * The str_initialize function is used to create the hash table and
- X * initialize it to empty.
- X *
- X * RETURNS
- X * void
- X *
- X * CAVEAT
- X * This function must be called before any other defined in this file.
- X */
- X
- Xvoid
- Xstr_initialize()
- X{
- X str_hash_ty j;
- X
- X hash_modulus = 1 << 8; /* MUST be a power of 2 */
- X hash_cutover = hash_modulus;
- X hash_split = hash_modulus - hash_cutover;
- X hash_cutover_mask = hash_cutover - 1;
- X hash_cutover_split_mask = (hash_cutover * 2) - 1;
- X hash_load = 0;
- X hash_table = (string_ty **)mem_alloc(hash_modulus * sizeof(string_ty *));
- X for (j = 0; j < hash_modulus; ++j)
- X hash_table[j] = 0;
- X
- X str_true = str_from_c("1");
- X str_false = str_from_c("");
- X}
- X
- X
- X/*
- X * NAME
- X * split - reduce table loading
- X *
- X * SYNOPSIS
- X * void split(void);
- X *
- X * DESCRIPTION
- X * The split function is used to reduce the load factor on the hash table.
- X *
- X * RETURNS
- X * void
- X *
- X * CAVEAT
- X * A load factor of about 80% is suggested.
- X */
- X
- Xstatic void split _((void));
- X
- Xstatic void
- Xsplit()
- X{
- X string_ty *p;
- X string_ty *p2;
- X str_hash_ty index;
- X
- X /*
- X * get the list to be split across buckets
- X */
- X p = hash_table[hash_split];
- X hash_table[hash_split] = 0;
- X
- X /*
- X * increase the modulus by one
- X */
- X hash_modulus++;
- X mem_change_size
- X (
- X (char **)&hash_table,
- X hash_modulus * sizeof(string_ty *)
- X );
- X hash_table[hash_modulus - 1] = 0;
- X hash_split = hash_modulus - hash_cutover;
- X if (hash_split >= hash_cutover)
- X {
- X hash_cutover = hash_modulus;
- X hash_split = 0;
- X hash_cutover_mask = hash_cutover - 1;
- X hash_cutover_split_mask = (hash_cutover * 2) - 1;
- X }
- X
- X /*
- X * now redistribute the list elements
- X */
- X while (p)
- X {
- X p2 = p;
- X p = p->str_next;
- X
- X index = p2->str_hash & hash_cutover_mask;
- X if (index < hash_split)
- X index = p2->str_hash & hash_cutover_split_mask;
- X assert(index < hash_modulus);
- X p2->str_next = hash_table[index];
- X hash_table[index] = p2;
- X }
- X}
- X
- X
- X/*
- X * NAME
- X * str_from_c - make string from C string
- X *
- X * SYNOPSIS
- X * string_ty *str_from_c(char*);
- X *
- X * DESCRIPTION
- X * The str_from_c function is used to make a string from a null terminated
- X * C string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_from_c(s)
- X char *s;
- X{
- X return str_n_from_c(s, strlen(s));
- X}
- X
- X
- X/*
- X * NAME
- X * str_n_from_c - make string
- X *
- X * SYNOPSIS
- X * string_ty *str_n_from_c(char *s, size_t n);
- X *
- X * DESCRIPTION
- X * The str_n_from_c function is used to make a string from an array of
- X * characters. No null terminator is assumed.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_n_from_c(s, length)
- X char *s;
- X size_t length;
- X{
- X str_hash_ty hash;
- X str_hash_ty index;
- X string_ty *p;
- X
- X hash = hash_generate(s, length);
- X
- X#ifdef DEBUG
- X if (!hash_table)
- X fatal("you must call str_initialize early in main()");
- X#endif
- X index = hash & hash_cutover_mask;
- X if (index < hash_split)
- X index = hash & hash_cutover_split_mask;
- X assert(index < hash_modulus);
- X
- X for (p = hash_table[index]; p; p = p->str_next)
- X {
- X if
- X (
- X p->str_hash == hash
- X &&
- X p->str_length == length
- X &&
- X !memcmp(p->str_text, s, length)
- X )
- X {
- X p->str_references++;
- X return p;
- X }
- X }
- X
- X p = (string_ty *)mem_alloc(sizeof(string_ty) + length);
- X p->str_hash = hash;
- X p->str_length = length;
- X p->str_references = 1;
- X p->str_next = hash_table[index];
- X hash_table[index] = p;
- X memcpy(p->str_text, s, length);
- X p->str_text[length] = 0;
- X
- X hash_load++;
- X while (hash_load * 10 > hash_modulus * 8)
- X split();
- X return p;
- X}
- X
- X
- X/*
- X * NAME
- X * str_copy - make a copy of a string
- X *
- X * SYNOPSIS
- X * string_ty *str_copy(string_ty *s);
- X *
- X * DESCRIPTION
- X * The str_copy function is used to make a copy of a string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_copy(s)
- X string_ty *s;
- X{
- X s->str_references++;
- X return s;
- X}
- X
- X
- X/*
- X * NAME
- X * str_free - release a string
- X *
- X * SYNOPSIS
- X * void str_free(string_ty *s);
- X *
- X * DESCRIPTION
- X * The str_free function is used to indicate that a string hash been
- X * finished with.
- X *
- X * RETURNS
- X * void
- X *
- X * CAVEAT
- X * This is the only way to release strings DO NOT use the free function.
- X */
- X
- Xvoid
- Xstr_free(s)
- X string_ty *s;
- X{
- X str_hash_ty index;
- X string_ty **spp;
- X
- X assert(str_valid(s));
- X if (s->str_references > 1)
- X {
- X s->str_references--;
- X return;
- X }
- X assert(s->str_references == 1);
- X
- X /*
- X * find the hash bucket it was in,
- X * and remove it
- X */
- X index = s->str_hash & hash_cutover_mask;
- X if (index < hash_split)
- X index = s->str_hash & hash_cutover_split_mask;
- X assert(index < hash_modulus);
- X for (spp = &hash_table[index]; *spp; spp = &(*spp)->str_next)
- X {
- X if (*spp == s)
- X {
- X *spp = s->str_next;
- X free(s);
- X --hash_load;
- X return;
- X }
- X }
- X /* should never reach here! */
- X fatal("attempted to free non-existent string (bug)");
- X}
- X
- X
- X/*
- X * NAME
- X * str_catenate - join two strings
- X *
- X * SYNOPSIS
- X * string_ty *str_catenate(string_ty *, string_ty *);
- X *
- X * DESCRIPTION
- X * The str_catenate function is used to concatenate two strings to form a
- X * new string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_catenate(s1, s2)
- X string_ty *s1;
- X string_ty *s2;
- X{
- X static char *tmp;
- X static size_t tmplen;
- X string_ty *s;
- X size_t length;
- X
- X length = s1->str_length + s2->str_length;
- X if (!tmp)
- X {
- X tmplen = length;
- X if (tmplen < 16)
- X tmplen = 16;
- X tmp = mem_alloc(tmplen);
- X }
- X else
- X {
- X if (tmplen < length)
- X {
- X tmplen = length;
- X mem_change_size(&tmp, tmplen);
- X }
- X }
- X memcpy(tmp, s1->str_text, s1->str_length);
- X memcpy(tmp + s1->str_length, s2->str_text, s2->str_length);
- X s = str_n_from_c(tmp, length);
- X return s;
- X}
- X
- X
- X/*
- X * NAME
- X * str_cat_three - join three strings
- X *
- X * SYNOPSIS
- X * string_ty *str_cat_three(string_ty *, string_ty *, string_ty *);
- X *
- X * DESCRIPTION
- X * The str_cat_three function is used to concatenate three strings to form
- X * a new string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_cat_three(s1, s2, s3)
- X string_ty *s1;
- X string_ty *s2;
- X string_ty *s3;
- X{
- X static char *tmp;
- X static size_t tmplen;
- X string_ty *s;
- X size_t length;
- X
- X length = s1->str_length + s2->str_length + s3->str_length;
- X if (!tmp)
- X {
- X tmplen = length;
- X if (tmplen < 16)
- X tmplen = 16;
- X tmp = mem_alloc(tmplen);
- X }
- X else
- X {
- X if (tmplen < length)
- X {
- X tmplen = length;
- X mem_change_size(&tmp, tmplen);
- X }
- X }
- X memcpy(tmp, s1->str_text, s1->str_length);
- X memcpy(tmp + s1->str_length, s2->str_text, s2->str_length);
- X memcpy
- X (
- X tmp + s1->str_length + s2->str_length,
- X s3->str_text,
- X s3->str_length
- X );
- X s = str_n_from_c(tmp, length);
- X return s;
- X}
- X
- X
- X/*
- X * NAME
- X * str_equal - test equality of strings
- X *
- X * SYNOPSIS
- X * int str_equal(string_ty *, string_ty *);
- X *
- X * DESCRIPTION
- X * The str_equal function is used to test if two strings are equal.
- X *
- X * RETURNS
- X * int; zero if the strings are not equal, nonzero if the strings are
- X * equal.
- X *
- X * CAVEAT
- X * This function is implemented as a macro in strings.h
- X */
- X
- X#ifndef str_equal
- X
- Xint
- Xstr_equal(s1, s2)
- X string_ty *s1;
- X string_ty *s2;
- X{
- X return (s1 == s2);
- X}
- X
- X#endif
- X
- X
- X/*
- X * NAME
- X * str_upcase - upcase a string
- X *
- X * SYNOPSIS
- X * string_ty *str_upcase(string_ty *);
- X *
- X * DESCRIPTION
- X * The str_upcase function is used to form a string which is an upper case
- X * form of the supplied string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_upcase(s)
- X string_ty *s;
- X{
- X static char *tmp;
- X static size_t tmplen;
- X string_ty *retval;
- X char *cp1;
- X char *cp2;
- X
- X if (!tmp)
- X {
- X tmplen = s->str_length;
- X if (tmplen < 16)
- X tmplen = 16;
- X tmp = mem_alloc(tmplen);
- X }
- X else
- X {
- X if (tmplen < s->str_length)
- X {
- X tmplen = s->str_length;
- X mem_change_size(&tmp, tmplen);
- X }
- X }
- X for (cp1 = s->str_text, cp2 = tmp; *cp1; ++cp1, ++cp2)
- X {
- X int c;
- X
- X c = *cp1;
- X if (c >= 'a' && c <= 'z')
- X c += 'A' - 'a';
- X *cp2 = c;
- X }
- X retval = str_n_from_c(tmp, s->str_length);
- X return retval;
- X}
- X
- X
- X/*
- X * NAME
- X * str_downcase - lowercase string
- X *
- X * SYNOPSIS
- X * string_ty *str_downcase(string_ty *);
- X *
- X * DESCRIPTION
- X * The str_downcase function is used to form a string which is a lowercase
- X * form of the supplied string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X *
- X * CAVEAT
- X * The contents of the structure pointed to MUST NOT be altered.
- X */
- X
- Xstring_ty *
- Xstr_downcase(s)
- X string_ty *s;
- X{
- X static char *tmp;
- X static size_t tmplen;
- X string_ty *retval;
- X char *cp1;
- X char *cp2;
- X
- X if (!tmp)
- X {
- X tmplen = s->str_length;
- X if (tmplen < 16)
- X tmplen = 16;
- X tmp = mem_alloc(tmplen);
- X }
- X else
- X {
- X if (tmplen < s->str_length)
- X {
- X tmplen = s->str_length;
- X mem_change_size(&tmp, tmplen);
- X }
- X }
- X for (cp1 = s->str_text, cp2 = tmp; *cp1; ++cp1, ++cp2)
- X {
- X int c;
- X
- X c = *cp1;
- X if (c >= 'A' && c <= 'Z')
- X c += 'a' - 'A';
- X *cp2 = c;
- X }
- X retval = str_n_from_c(tmp, s->str_length);
- X return retval;
- X}
- X
- X
- X/*
- X * NAME
- X * str_bool - get boolean value
- X *
- X * SYNOPSIS
- X * int str_bool(string_ty *s);
- X *
- X * DESCRIPTION
- X * The str_bool function is used to determine the boolean value of the
- X * given string. A "false" result is if the string is empty or
- X * 0 or blank, and "true" otherwise.
- X *
- X * RETURNS
- X * int: zero to indicate a "false" result, nonzero to indicate a "true"
- X * result.
- X */
- X
- Xint
- Xstr_bool(s)
- X string_ty *s;
- X{
- X char *cp;
- X
- X cp = s->str_text;
- X while (*cp)
- X {
- X if (*cp != ' ' && *cp != '0')
- X return 1;
- X ++cp;
- X }
- X return 0;
- X}
- X
- X
- X/*
- X * NAME
- X * str_field - extract a field from a string
- X *
- X * SYNOPSIS
- X * string_ty *str_field(string_ty *, char separator, int field_number);
- X *
- X * DESCRIPTION
- X * The str_field functipon is used to erxtract a field from a string.
- X * Fields of the string are separated by ``separator'' characters.
- X * Fields are numbered from 0.
- X *
- X * RETURNS
- X * Asking for a field off the end of the string will result in a null
- X * pointer return. The null string is considered to have one empty field.
- X */
- X
- Xstring_ty *
- Xstr_field(s, sep, fldnum)
- X string_ty *s;
- X int sep;
- X int fldnum;
- X{
- X char *cp;
- X char *ep;
- X
- X cp = s->str_text;
- X while (fldnum > 0)
- X {
- X ep = strchr(cp, sep);
- X if (!ep)
- X return 0;
- X cp = ep + 1;
- X --fldnum;
- X }
- X ep = strchr(cp, sep);
- X if (ep)
- X return str_n_from_c(cp, ep - cp);
- X return str_from_c(cp);
- X}
- X
- X
- X/*
- X * NAME
- X * str_format - analog of sprintf
- X *
- X * SYNOPSIS
- X * string_ty *str_format(char *, ...);
- X *
- X * DESCRIPTION
- X * The str_format function is used to create new strings
- X * using a format specification similar to printf(3).
- X * The "%S" specifier is used to mean a ``string_ty *'' string.
- X *
- X * RETURNS
- X * string_ty * - a pointer to a string in dynamic memory. Use str_free when
- X * finished with.
- X */
- X
- X
- Xstring_ty *
- Xstr_format(fmt sva_last)
- X char *fmt;
- X sva_last_decl
- X{
- X va_list ap;
- X string_ty *result;
- X
- X sva_init(ap, fmt);
- X result = str_vformat(fmt, ap);
- X va_end(ap);
- X return result;
- X}
- X
- X
- Xstatic void build_fake _((char *fake, int flag, int width, int precision,
- X int qualifier, int specifier));
- X
- Xstatic void
- Xbuild_fake(fake, flag, width, precision, qualifier, specifier)
- X char *fake;
- X int flag;
- X int width;
- X int precision;
- X int qualifier;
- X int specifier;
- X{
- X char *fp;
- X
- X fp = fake;
- X *fp++ = '%';
- X if (flag)
- X *fp++ = flag;
- X if (width > 0)
- X {
- X sprintf(fp, "%d", width);
- X fp += strlen(fp);
- X }
- X *fp++ = '.';
- X sprintf(fp, "%d", precision);
- X fp += strlen(fp);
- X if (qualifier)
- X *fp++ = qualifier;
- X *fp++ = specifier;
- X *fp = 0;
- X}
- X
- X
- Xstring_ty *
- Xstr_vformat(fmt, ap)
- X char *fmt;
- X va_list ap;
- X{
- X size_t length;
- X static size_t tmplen;
- X static char *tmp;
- X int width;
- X int width_set;
- X int prec;
- X int prec_set;
- X int c;
- X char *s;
- X int qualifier;
- X int flag;
- X char fake[100];
- X
- X /*
- X * Build the result string in a temporary buffer.
- X * Grow the temporary buffer as necessary.
- X *
- X * It is important to only make one pass across the variable argument
- X * list. Behaviour is undefined for more than one pass.
- X */
- X if (!tmplen)
- X {
- X tmplen = 500;
- X tmp = mem_alloc(tmplen);
- X }
- X length = 0;
- X s = fmt;
- X while (*s)
- X {
- X c = *s++;
- X if (c != '%')
- X {
- X normal:
- X if (length >= tmplen)
- X {
- X tmplen += 100;
- X mem_change_size(&tmp, tmplen);
- X }
- X tmp[length++] = c;
- X continue;
- X }
- X c = *s++;
- X
- X /*
- X * get optional flag
- X */
- X switch (c)
- X {
- X case '+':
- X case '-':
- X case '#':
- X case '0':
- X case ' ':
- X flag = c;
- X c = *s++;
- X break;
- X
- X default:
- X flag = 0;
- X break;
- X }
- X
- X /*
- X * get optional width
- X */
- X width = 0;
- X width_set = 0;
- X switch (c)
- X {
- X case '*':
- X width = va_arg(ap, int);
- X if (width < 0)
- X {
- X flag = '-';
- X width = -width;
- X }
- X c = *s++;
- X width_set = 1;
- X break;
- X
- X case '0': case '1': case '2': case '3': case '4':
- X case '5': case '6': case '7': case '8': case '9':
- X for (;;)
- X {
- X width = width * 10 + c - '0';
- X c = *s++;
- X switch (c)
- X {
- X default:
- X break;
- X
- X case '0': case '1': case '2': case '3':
- X case '4': case '5': case '6': case '7':
- X case '8': case '9':
- X continue;
- X }
- X break;
- X }
- X width_set = 1;
- X break;
- X
- X default:
- X break;
- X }
- X
- X /*
- X * get optional precision
- X */
- X prec = 0;
- X prec_set = 0;
- X if (c == '.')
- X {
- X c = *s++;
- X switch (c)
- X {
- X default:
- X prec_set = 1;
- X break;
- X
- X case '*':
- X c = *s++;
- X prec = va_arg(ap, int);
- X if (prec < 0)
- X {
- X prec = 0;
- X break;
- X }
- X prec_set = 1;
- X break;
- X
- X case '0': case '1': case '2': case '3': case '4':
- X case '5': case '6': case '7': case '8': case '9':
- X for (;;)
- X {
- X prec = prec * 10 + c - '0';
- X c = *s++;
- X switch (c)
- X {
- X default:
- X break;
- X
- X case '0': case '1': case '2': case '3':
- X case '4': case '5': case '6': case '7':
- X case '8': case '9':
- X continue;
- X }
- X break;
- X }
- X prec_set = 1;
- X break;
- X }
- X }
- X
- X /*
- X * get the optional qualifier
- X */
- X switch (c)
- X {
- X default:
- X qualifier = 0;
- X break;
- X
- X case 'l':
- X case 'h':
- X case 'L':
- X qualifier = c;
- X c = *s++;
- X break;
- X }
- X
- X /*
- X * get conversion specifier
- X */
- X switch (c)
- X {
- X default:
- X fatal
- X (
- X "in format string \"%s\", illegal specifier '%c'",
- X fmt,
- X c
- X );
- X
- X case '%':
- X goto normal;
- X
- X case 'c':
- X {
- X int a;
- X char num[MAX_WIDTH + 1];
- X size_t len;
- X
- X a = (unsigned char)va_arg(ap, int);
- X if (!prec_set)
- X prec = 1;
- X if (width > MAX_WIDTH)
- X width = MAX_WIDTH;
- X if (prec > MAX_WIDTH)
- X prec = MAX_WIDTH;
- X build_fake(fake, flag, width, prec, 0, c);
- X sprintf(num, fake, a);
- X len = strlen(num);
- X if (length + len > tmplen)
- X {
- X tmplen += len;
- X mem_change_size(&tmp, tmplen);
- X }
- X memcpy(tmp + length, num, len);
- X length += len;
- X }
- X break;
- X
- X case 'd':
- X case 'i':
- X {
- X long a;
- X char num[MAX_WIDTH + 1];
- X size_t len;
- X
- X switch (qualifier)
- X {
- X case 'l':
- X a = va_arg(ap, long);
- X break;
- X
- X case 'h':
- X a = (short)va_arg(ap, int);
- X break;
- X
- X default:
- X a = va_arg(ap, int);
- X break;
- X }
- X if (!prec_set)
- X prec = 1;
- X if (width > MAX_WIDTH)
- X width = MAX_WIDTH;
- X if (prec > MAX_WIDTH)
- X prec = MAX_WIDTH;
- X build_fake(fake, flag, width, prec, 'l', c);
- X sprintf(num, fake, a);
- X len = strlen(num);
- X if (length + len > tmplen)
- X {
- X tmplen += len;
- X mem_change_size(&tmp, tmplen);
- X }
- X memcpy(tmp + length, num, len);
- X length += len;
- X }
- X break;
- X
- X case 'e':
- X case 'f':
- X case 'g':
- X case 'E':
- X case 'F':
- X case 'G':
- X {
- X double a;
- X char num[MAX_WIDTH + 1];
- X size_t len;
- X
- X /*
- X * Ignore "long double" for now,
- X * traditional implementations no grok.
- X */
- X a = va_arg(ap, double);
- X if (!prec_set)
- X prec = 6;
- X if (width > MAX_WIDTH)
- X width = MAX_WIDTH;
- X if (prec > MAX_WIDTH)
- X prec = MAX_WIDTH;
- X build_fake(fake, flag, width, prec, 0, c);
- X sprintf(num, fake, a);
- X len = strlen(num);
- X if (length + len > tmplen)
- X {
- X tmplen += len;
- X mem_change_size(&tmp, tmplen);
- X }
- X memcpy(tmp + length, num, len);
- X length += len;
- X }
- X break;
- X
- X case 'n':
- X switch (qualifier)
- X {
- X case 'l':
- X {
- X long *a;
- X
- X a = va_arg(ap, long *);
- X *a = length;
- X }
- X break;
- X
- X case 'h':
- X {
- X short *a;
- X
- X a = va_arg(ap, short *);
- X *a = length;
- X }
- X break;
- X
- X default:
- X {
- X int *a;
- X
- X a = va_arg(ap, int *);
- X *a = length;
- X }
- X break;
- X }
- X break;
- X
- X case 'u':
- X case 'o':
- X case 'x':
- X case 'X':
- X {
- X unsigned long a;
- X char num[MAX_WIDTH + 1];
- X size_t len;
- X
- X switch (qualifier)
- X {
- X case 'l':
- X a = va_arg(ap, unsigned long);
- X break;
- X
- X case 'h':
- X a = (unsigned short)va_arg(ap, unsigned int);
- X break;
- X
- X default:
- X a = va_arg(ap, unsigned int);
- X break;
- X }
- X if (!prec_set)
- X prec = 1;
- X if (prec > MAX_WIDTH)
- X prec = MAX_WIDTH;
- X if (width > MAX_WIDTH)
- X width = MAX_WIDTH;
- X build_fake(fake, flag, width, prec, 'l', c);
- X sprintf(num, fake, a);
- X len = strlen(num);
- X if (length + len > tmplen)
- X {
- X tmplen += len;
- X mem_change_size(&tmp, tmplen);
- X }
- X memcpy(tmp + length, num, len);
- X length += len;
- X }
- X break;
- X
- X case 's':
- X {
- X char *a;
- X size_t len;
- X
- X a = va_arg(ap, char *);
- X if (prec_set)
- X {
- X char *ep;
- X
- X ep = (char *)memchr(a, 0, prec);
- X if (ep)
- X len = ep - a;
- X else
- X len = prec;
- X }
- X else
- X len = strlen(a);
- X if (!prec_set || len < prec)
- X prec = len;
- X if (!width_set || width < prec)
- X width = prec;
- X len = width;
- X if (length + len > tmplen)
- X {
- X tmplen += len;
- X mem_change_size(&tmp, tmplen);
- X }
- X if (flag != '-')
- X {
- X while (width > prec)
- X {
- X tmp[length++] = ' ';
- X width--;
- X }
- X }
- X memcpy(tmp + length, a, prec);
- X length += prec;
- X width -= prec;
- X if (flag == '-')
- X {
- X while (width > 0)
- X {
- X tmp[length++] = ' ';
- X width--;
- X }
- X }
- X }
- X break;
- X
- X case 'S':
- X {
- X string_ty *a;
- X size_t len;
- X
- X a = va_arg(ap, string_ty *);
- X len = a->str_length;
- X if (!prec_set)
- X prec = len;
- X if (len < prec)
- X prec = len;
- X if (!width_set)
- X width = prec;
- X if (width < prec)
- X width = prec;
- X len = width;
- X if (length + len > tmplen)
- X {
- X tmplen += len;
- X mem_change_size(&tmp, tmplen);
- X }
- X if (flag != '-')
- X {
- X while (width > prec)
- X {
- X tmp[length++] = ' ';
- X width--;
- X }
- X }
- X memcpy(tmp + length, a->str_text, prec);
- X length += prec;
- X width -= prec;
- X if (flag == '-')
- X {
- X while (width > 0)
- X {
- X tmp[length++] = ' ';
- X width--;
- X }
- X }
- X }
- X break;
- X }
- X }
- X
- X /*
- X * make the string
- X */
- X assert(length <= tmplen);
- X return str_n_from_c(tmp, length);
- X}
- END_OF_FILE
- if test 22749 -ne `wc -c <'common/str.c'`; then
- echo shar: \"'common/str.c'\" unpacked with wrong size!
- fi
- # end of 'common/str.c'
- fi
- if test -f 'cook/main.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cook/main.c'\"
- else
- echo shar: Extracting \"'cook/main.c'\" \(17856 characters\)
- sed "s/^X//" >'cook/main.c' <<'END_OF_FILE'
- X/*
- X * cook - file construction tool
- X * Copyright (C) 1991, 1992, 1993 Peter Miller.
- X * All rights reserved.
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of the GNU General Public License as published by
- X * the Free Software Foundation; either version 2 of the License, or
- X * (at your option) any later version.
- X *
- X * This program is distributed in the hope that it will be useful,
- X * but WITHOUT ANY WARRANTY; without even the implied warranty of
- X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X * GNU General Public License for more details.
- X *
- X * You should have received a copy of the GNU General Public License
- X * along with this program; if not, write to the Free Software
- X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X *
- X * MANIFEST: operating system start point, and command line argument parsing
- X */
- X
- X#include <stddef.h>
- X#include <string.h>
- X#include <stdio.h>
- X#include <stdlib.h>
- X
- X#include <arglex.h>
- X#include <builtin.h>
- X#include <cook.h>
- X#include <env.h>
- X#include <error.h>
- X#include <help.h>
- X#include <id.h>
- X#include <lex.h>
- X#include <listing.h>
- X#include <main.h>
- X#include <option.h>
- X#include <parse.h>
- X#include <trace.h>
- X#include <version.h>
- X
- X
- Xenum
- X{
- X arglex_token_action,
- X arglex_token_no_action,
- X arglex_token_book,
- X arglex_token_no_book,
- X arglex_token_errok,
- X arglex_token_no_errok,
- X arglex_token_force,
- X arglex_token_no_force,
- X arglex_token_include,
- X arglex_token_log,
- X arglex_token_no_log,
- X arglex_token_metering,
- X arglex_token_no_metering,
- X arglex_token_persevere,
- X arglex_token_no_persevere,
- X arglex_token_precious,
- X arglex_token_no_precious,
- X arglex_token_silent,
- X arglex_token_no_silent,
- X arglex_token_touch,
- X arglex_token_no_touch,
- X arglex_token_trace,
- X arglex_token_no_trace,
- X arglex_token_tty,
- X arglex_token_no_tty
- X};
- X
- Xstatic arglex_table_ty argtab[] =
- X{
- X { "-Action", (arglex_token_ty)arglex_token_action, },
- X { "-No_Action", (arglex_token_ty)arglex_token_no_action, },
- X { "-Book", (arglex_token_ty)arglex_token_book, },
- X { "-No_Book", (arglex_token_ty)arglex_token_no_book, },
- X { "-Continue", (arglex_token_ty)arglex_token_persevere, },
- X { "-No_Continue", (arglex_token_ty)arglex_token_no_persevere, },
- X { "-Errok", (arglex_token_ty)arglex_token_errok, },
- X { "-No_Errok", (arglex_token_ty)arglex_token_no_errok, },
- X { "-Forced", (arglex_token_ty)arglex_token_force, },
- X { "-No_Forced", (arglex_token_ty)arglex_token_no_force, },
- X { "-LOg", (arglex_token_ty)arglex_token_log, },
- X { "-List", (arglex_token_ty)arglex_token_log, },
- X { "-No_LOg", (arglex_token_ty)arglex_token_no_log, },
- X { "-No_List", (arglex_token_ty)arglex_token_no_log, },
- X { "-Meter", (arglex_token_ty)arglex_token_metering, },
- X { "-No_Meter", (arglex_token_ty)arglex_token_no_metering, },
- X { "-Precious", (arglex_token_ty)arglex_token_precious, },
- X { "-No_Precious", (arglex_token_ty)arglex_token_no_precious, },
- X { "-Silent", (arglex_token_ty)arglex_token_silent, },
- X { "-No_Silent", (arglex_token_ty)arglex_token_no_silent, },
- X { "-Touch", (arglex_token_ty)arglex_token_touch, },
- X { "-No_Touch", (arglex_token_ty)arglex_token_no_touch, },
- X { "-TRace", (arglex_token_ty)arglex_token_trace, },
- X { "-No_TRace", (arglex_token_ty)arglex_token_no_trace, },
- X { "-TErminal", (arglex_token_ty)arglex_token_tty, },
- X { "-No_TErminal", (arglex_token_ty)arglex_token_no_tty, },
- X { "-Include", (arglex_token_ty)arglex_token_include, },
- X { "-\\I*", (arglex_token_ty)arglex_token_include, },
- X { 0, (arglex_token_ty)0, }, /* end marker */
- X};
- X
- X
- X/*
- X * NAME
- X * usage - options diagnostic
- X *
- X * SYNOPSIS
- X * void usage(void);
- X *
- X * DESCRIPTION
- X * Usage is called when the user has made a syntactic or semantic error
- X * on the command line.
- X *
- X * CAVEAT
- X * This function does NOT return.
- X */
- X
- Xstatic void usage _((void));
- X
- Xstatic void
- Xusage()
- X{
- X fprintf(stderr, "usage: %s [ <option>... ][ <filename>... ]\n", progname);
- X fprintf(stderr, " %s -Help\n", progname);
- X fprintf(stderr, " %s -VERSion\n", progname);
- X quit(1);
- X}
- X
- X
- X/*
- X * NAME
- X * help - give some
- X *
- X * SYNOPSIS
- X * void help(void);
- X *
- X * DESCRIPTION
- X * Help is used to provide the use with some assistance.
- X *
- X * RETURNS
- X * void
- X *
- X * CAVEAT
- X * Assumes os_get_search_rules has been called already.
- X */
- X
- Xstatic void cook_help _((void));
- X
- Xstatic void
- Xcook_help()
- X{
- X static char *text[] =
- X {
- X"NAME",
- X" %s - a file construction tool",
- X"",
- X"SYNOPSIS",
- X" %s [ <option>... ][ <filename>... ]",
- X" %s -Help",
- X" %s -VERSion",
- X"",
- X"DESCRIPTION",
- X" The %s program is a tool for constructing files. It is",
- X" given a set of files to create, and instructions",
- X" detailing how to construct them. In any non-trivial",
- X" program there will be prerequisites to performing the",
- X" actions necessary to creating any file, such as",
- X" extraction from a source-control system. The %s",
- X" program provides a mechanism to define these.",
- X"",
- X" When a program is being developed or maintained, the",
- X" programmer will typically change one file of several",
- X" which comprise the program. The %s program examines",
- X" the last-modified times of the files to see when the",
- X" prerequisites of a file have changed, implying that the",
- X" file needs to be recreated as it is logically out of",
- X" date.",
- X"",
- X" The %s program also provides a facility for implicit",
- X" recipes, allowing users to specify how to form a file",
- X" with a given suffix from a file with a different suffix.",
- X" For example, to create filename.o from filename.c",
- X"",
- X" Options and filenames may be arbitrarily mixed on the",
- X" command line; no processing is done until all options and",
- X" filenames on the command line have been scanned.",
- X"",
- X" The %s program will attempt to create the named files",
- X" from the recipes given to it. The recipes are contained",
- X" in a file called Howto.%s in the currect directory.",
- X" This file may, in turn, include other files containing",
- X" additional recipes.",
- X"",
- X" If no filenames are given on the command line the targets",
- X" of the first recipe defined are cooked.",
- X"",
- X"OPTIONS",
- X" The valid options for %s are listed below. Any other",
- X" options (words on the command line beginning with `-')",
- X" will cause a diagnostic message to be issued.",
- X"",
- X" -Action",
- X" Execute the commands given in the recipes. This",
- X" is the default.",
- X"",
- X" -No_Action",
- X" Do not execute the commands given in the recipes.",
- X"",
- X" -Book <filename>",
- X" Tells %s to used the named cookbook, rather than",
- X" the default ``Howto.cook'' file.",
- X"",
- X" -Continue",
- X" If cooking a target should fail, continue with",
- X" other recipes for which the failed target is not",
- X" an ingredient, directly or indirectly.",
- X"",
- X" -No_Continue",
- X" If cooking a target should fail, %s will exit.",
- X" This is the default.",
- X"",
- X" -Errok",
- X" When a command is executed, the exit code will be",
- X" ignored.",
- X"",
- X" -No_Errok",
- X" When a command is executed, if the exit code is",
- X" positive it will be deemed to fail, and thus the",
- X" recipe containing it to have failed. This is the",
- X" default.",
- X"",
- X" -Force",
- X" Always perform the actions of recipes,",
- X" irrespective of the last-modified times of any of",
- X" the ingredients. This option is useful if",
- X" something beyond the scope of the cookbook has",
- X" been modified; for example, a bug fix in a",
- X" compiler.",
- X"",
- X" -No_Force",
- X" Perform the actions of the recipes if any of the",
- X" ingredients are logically out of date. This is",
- X" the default.",
- X"",
- X" -Help",
- X" Provide information about how to execute %s on",
- X" stdout, and perform no other function.",
- X"",
- X" -Include <filename>",
- X" Search the named directory before the standard",
- X" places for included cookbooks. Each directory so",
- X" named will be scanned in the order given. The",
- X" standard places are $HOME/.%s then",
- X" /usr/local/lib/cook.",
- X"",
- X" -List",
- X" Causes %s to automatically redirect the stdout",
- X" and stderr of the session. Output will continue",
- X" to come to the terminal, unless %s is executing",
- X" in the background. The name of the file will be",
- X" the name of the cookbook with any suffix removed",
- X" and \".list\" appended; this will usually be",
- X" Howto.list. This is the default.",
- X"",
- X" -List <filename>",
- X" Causes %s to automatically redirect the stdout",
- X" and stderr of the session into the named file.",
- X" Output will continue to come to the terminal,",
- X" unless %s is executing in the background.",
- X"",
- X" -No_List",
- X" No automatic redirection of the output of the",
- X" session will be made.",
- X"",
- X" -No_List <filename>",
- X" No automatic redirection of the output of the",
- X" session will be made, however subsequent -List",
- X" options will default to listing to the named",
- X" file.",
- X"",
- X" -Meter",
- X" After each command is executed, print a summary",
- X" of the command's CPU usage.",
- X"",
- X" -No_Meter",
- X" Do not print a CPU usage summary after each",
- X" command. This is the default.",
- X"",
- X" -Precious",
- X" When commands in the body of a recipe fail, do",
- X" not delete the targets of the recipe.",
- X"",
- X" -No_Precious",
- X" When commands in the body of a recipe fail,",
- X" delete the targets of the recipe. This is the",
- X" default.",
- X"",
- X" -Silent",
- X" Do not echo commands before they are executed.",
- X"",
- X" -No_Silent",
- X" Echo commands before they are executed. This is",
- X" the default.",
- X"",
- X" -Touch",
- X" Update the last-modified times of the target",
- X" files, rather than execute the actions bound to",
- X" recipes. This can be useful if you have made a",
- X" modification to a file that you know will make a",
- X" system of files logically out of date, but has no",
- X" significance; for example, adding a comment to a",
- X" widely used include file.",
- X"",
- X" -No_Touch",
- X" Execute the actions bound to recipes, rather than",
- X" update the last-modified times of the target",
- X" files. This is the default.",
- X"",
- X" -TErminal",
- X" When listing, also send the output stream to the",
- X" terminal. This is the default.",
- X"",
- X" -No_TErminal",
- X" When listing, do not send the output to the",
- X" terminal.",
- X"",
- X" name=value",
- X" Assign the value to the named variable. The",
- X" value may contain spaces if you can convince the",
- X" shell to pass them through.",
- X"",
- X" -TRace",
- X" Two options are provided for tracing the",
- X" inferences %s makes when attempting to %s a",
- X" target. The -TRace option will cause %s will",
- X" emit copious amounts of information about the",
- X" inferences it is making when cooking targets.",
- X" This option may be used when you think %s is",
- X" acting strangely, or are just curious.",
- X"",
- X" -No_TRace",
- X" This option may be used to cause %s will not",
- X" emit information about the inferences it is",
- X" making when cooking targets. This is the",
- X" default.",
- X"",
- X" All options may be abbreviated; the abbreviation is",
- X" documented as the upper case letters, all lower case",
- X" letters and underscores (_) are optional. You must use",
- X" consecutive sequences of optional letters.",
- X"",
- X" All options are case insensitive, you may type them in",
- X" upper case or lower case or a combination of both, case",
- X" is not important.",
- X"",
- X" For example: the arguments \"-help\", \"-HEL\" and \"-h\" are",
- X" all interpreted to mean the -Help option. The argument",
- X" \"-hlp\" will not be understood, because consecutive",
- X" optional characters were not supplied.",
- X"",
- X" Options and other command line arguments may be mixed",
- X" arbitrarily on the command line.",
- X"",
- X" The GNU long option names are understood. Since all",
- X" option names for %s are long, this means ignoring the",
- X" extra leading '-'. The \"--option=value\" convention is",
- X" also understood.",
- X"",
- X"EXIT STATUS",
- X" The %s command will exit with a status of 1 on any",
- X" error. The %s command will only exit with a status of",
- X" 0 if there are no errors.",
- X"",
- X"COPYRIGHT",
- X" %C",
- X"",
- X"AUTHOR",
- X" %A",
- X };
- X
- X help(text, SIZEOF(text), usage);
- X}
- X
- X
- X/*
- X * NAME
- X * argparse - parse command line
- X *
- X * SYNOPSIS
- X * void argparse(option_level_ty);
- X *
- X * DESCRIPTION
- X * The argparse function is used to parse command lines.
- X *
- X * RETURNS
- X * void
- X */
- X
- Xstatic void argparse _((option_level_ty));
- X
- Xstatic void
- Xargparse(level)
- X option_level_ty level;
- X{
- X option_number_ty type = -1;
- X
- X switch (arglex())
- X {
- X case arglex_token_help:
- X if (level != OPTION_LEVEL_COMMAND_LINE)
- X fatal("may not use %s in environment variable", arglex_value.alv_string);
- X cook_help();
- X quit(0);
- X
- X case arglex_token_version:
- X if (level != OPTION_LEVEL_COMMAND_LINE)
- X fatal("may not use %s in environment variable", arglex_value.alv_string);
- X version();
- X quit(0);
- X
- X default:
- X break;
- X }
- X while (arglex_token != arglex_token_eoln)
- X {
- X switch (arglex_token)
- X {
- X default:
- X error
- X (
- X "misplaced \"%s\" command line argument",
- X arglex_value.alv_string
- X );
- X usage();
- X
- X#ifdef DEBUG
- X case arglex_token_tracing:
- X if (arglex() != arglex_token_string)
- X fatal("-TRACIng requires one or more string arguments");
- X for (;;)
- X {
- X trace_enable(arglex_value.alv_string);
- X if (arglex() != arglex_token_string)
- X break;
- X }
- X continue;
- X#endif
- X
- X case arglex_token_include:
- X {
- X string_ty *s;
- X
- X if (arglex() != arglex_token_string)
- X fatal("-Include requires a string argument");
- X s = str_from_c(arglex_value.alv_string);
- X wl_append_unique(&option.o_search_path, s);
- X str_free(s);
- X }
- X break;
- X
- X case arglex_token_trace:
- X type = OPTION_TRACE;
- X normal_on:
- X if (option_already(type, level))
- X too_many:
- X fatal("too many \"%s\" options", arglex_value.alv_string);
- X option_set(type, level, 1);
- X break;
- X
- X case arglex_token_no_trace:
- X type = OPTION_TRACE;
- X normal_off:
- X if (option_already(type, level))
- X goto too_many;
- X option_set(type, level, 0);
- X break;
- X
- X case arglex_token_tty:
- X type = OPTION_TERMINAL;
- X goto normal_on;
- X
- X case arglex_token_no_tty:
- X type = OPTION_TERMINAL;
- X goto normal_off;
- X
- X case arglex_token_precious:
- X type = OPTION_PRECIOUS;
- X goto normal_on;
- X
- X case arglex_token_no_precious:
- X type = OPTION_PRECIOUS;
- X goto normal_off;
- X
- X case arglex_token_log:
- X if (option_already(OPTION_LOGGING, level))
- X goto too_many;
- X option_set(OPTION_LOGGING, level, 1);
- X if (arglex() != arglex_token_string)
- X continue;
- X if (option.o_logfile)
- X str_free(option.o_logfile);
- X option.o_logfile = str_from_c(arglex_value.alv_string);
- X break;
- X
- X case arglex_token_no_log:
- X type = OPTION_LOGGING;
- X goto normal_off;
- X
- X case arglex_token_book:
- X if (option_already(OPTION_BOOK, level))
- X goto too_many;
- X option_set(OPTION_BOOK, level, 1);
- X if (arglex() != arglex_token_string)
- X continue;
- X if (option.o_book)
- X str_free(option.o_book);
- X option.o_book = str_from_c(arglex_value.alv_string);
- X break;
- X
- X case arglex_token_no_book:
- X type = OPTION_BOOK;
- X goto normal_off;
- X
- X case arglex_token_silent:
- X type = OPTION_SILENT;
- X goto normal_on;
- X
- X case arglex_token_no_silent:
- X type = OPTION_SILENT;
- X goto normal_off;
- X
- X case arglex_token_metering:
- X type = OPTION_METER;
- X goto normal_on;
- X
- X case arglex_token_no_metering:
- X type = OPTION_METER;
- X goto normal_off;
- X
- X case arglex_token_touch:
- X type = OPTION_TOUCH;
- X goto normal_on;
- X
- X case arglex_token_no_touch:
- X type = OPTION_TOUCH;
- X goto normal_off;
- X
- X case arglex_token_action:
- X type = OPTION_ACTION;
- X goto normal_on;
- X
- X case arglex_token_no_action:
- X type = OPTION_ACTION;
- X goto normal_off;
- X
- X case arglex_token_persevere:
- X type = OPTION_PERSEVERE;
- X goto normal_on;
- X
- X case arglex_token_no_persevere:
- X type = OPTION_PERSEVERE;
- X goto normal_off;
- X
- X case arglex_token_errok:
- X type = OPTION_ERROK;
- X goto normal_on;
- X
- X case arglex_token_no_errok:
- X type = OPTION_ERROK;
- X goto normal_off;
- X
- X case arglex_token_force:
- X type = OPTION_FORCE;
- X goto normal_on;
- X
- X case arglex_token_no_force:
- X type = OPTION_FORCE;
- X goto normal_off;
- X
- X case arglex_token_string:
- X {
- X char *cp;
- X
- X cp = strchr(arglex_value.alv_string, '=');
- X if (!cp)
- X {
- X string_ty *s;
- X
- X s = str_from_c(arglex_value.alv_string);
- X wl_append(&option.o_target, s);
- X str_free(s);
- X }
- X else
- X {
- X wlist wl;
- X string_ty *name;
- X string_ty *value;
- X
- X name = str_n_from_c(
- X arglex_value.alv_string,
- X cp - arglex_value.alv_string
- X );
- X value = str_from_c(cp + 1);
- X str2wl(&wl, value);
- X str_free(value);
- X id_assign(name, ID_CLASS_VARIABLE, &wl);
- X str_free(name);
- X wl_free(&wl);
- X }
- X }
- X break;
- X }
- X arglex();
- X }
- X}
- X
- X
- X/*
- X * NAME
- X * main - initial entry point for cook
- X *
- X * SYNOPSIS
- X * void main(int argc, char **argv);
- X *
- X * DESCRIPTION
- X * Main is the initial entry point for cook.
- X *
- X * RETURNS
- X * Exit is always through exit().
- X * The exit code will be 0 for success, or 1 for some error.
- X */
- X
- Xint main _((int, char **));
- X
- Xint
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X int retval;
- X
- X /*
- X * initialize things
- X * (order is critical here)
- X */
- X#ifdef TIMING
- X os_totals_start();
- X#endif
- X arglex_set_progname(argv[0]);
- X env_initialize();
- X str_initialize();
- X id_initialize();
- X builtin_initialize();
- X lex_initialize();
- X parse_initialize();
- X
- X /*
- X * parse the command line
- X */
- X arglex_init_from_env(argv[0], argtab);
- X argparse(OPTION_LEVEL_ENVIRONMENT);
- X
- X /*
- X * parse the command line
- X */
- X arglex_init(argc, argv, argtab);
- X argparse(OPTION_LEVEL_COMMAND_LINE);
- X
- X option_tidy_up();
- X
- X log_open();
- X
- X /*
- X * read in the cook book
- X */
- X if (!option.o_book)
- X fatal("no book found");
- X parse(option.o_book);
- X
- X /*
- X * work out what to cook.
- X * If no targets have been given, use the first explicit recipe.
- X */
- X if (!option.o_target.wl_nwords)
- X {
- X if (!explicit.rl_nrecipes)
- X fatal("no default target");
- X wl_copy(&option.o_target, &explicit.rl_recipe[0].r_target);
- X }
- X assert(option.o_target.wl_nwords);
- X
- X retval = cook(&option.o_target);
- X
- X#ifdef TIMING
- X os_totals();
- X#endif
- X quit(retval);
- X /*NOTREACHED*/
- X return 0;
- X}
- END_OF_FILE
- if test 17856 -ne `wc -c <'cook/main.c'`; then
- echo shar: \"'cook/main.c'\" unpacked with wrong size!
- fi
- # end of 'cook/main.c'
- fi
- if test -f 'doc/language' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'doc/language'\"
- else
- echo shar: Extracting \"'doc/language'\" \(18062 characters\)
- sed "s/^X//" >'doc/language' <<'END_OF_FILE'
- X.\"
- X.\" cook - file construction tool
- X.\" Copyright (C) 1990, 1991, 1992, 1993 Peter Miller.
- X.\" All rights reserved.
- X.\"
- X.\" This program is free software; you can redistribute it and/or modify
- X.\" it under the terms of the GNU General Public License as published by
- X.\" the Free Software Foundation; either version 2 of the License, or
- X.\" (at your option) any later version.
- X.\"
- X.\" This program is distributed in the hope that it will be useful,
- X.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
- X.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X.\" GNU General Public License for more details.
- X.\"
- X.\" You should have received a copy of the GNU General Public License
- X.\" along with this program; if not, write to the Free Software
- X.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X.\"
- X.\" MANIFEST: Reference Manual, Cookbook Lanuage Definition
- X.\"
- X.H 1 "Cookbook Language Definition"
- XThis chapter defines that language which cookbooks
- Xare written in.
- XWhile some of its properties are similar to C,
- Xdo not be misled.
- X.P
- XA number of sections appear within this chapter.
- X.AL
- X.LI
- XThe
- X.I "Lexical Analysis"
- Xsection describes what the words of the cookbook language look like.
- X.LI
- XThe
- X.I Preprocessor
- Xsection describes
- Xthe include mechanism
- Xand the conditional compilation mechanism.
- X.LI
- XThe
- X.I "Syntax Descriptions"
- Xsection describes how to read the syntax definitions
- Xin the following section.
- X.LI
- XThe
- X.I "Syntax and Semantics"
- Xsection describes
- Xhow words in the cookbook may be combined to form valid constructs
- X(the
- X.IR syntax ),
- Xand what these constructs
- Xmean (the
- X.IR semantics ).
- X.LE
- X.P
- XThe sections are laid out in the recommended reading order.
- X.SK
- X.H 2 "Lexical Analysis"
- XThe cookbook is made of a number of recipes,
- Xwhich are in turn made of words.
- XThis section describes what constitutes a word, and what does not.
- X.H 3 "Words and Keywords"
- XWords are made of sequences of almost any character,
- Xand are separated by white space (including end-of-line) or the
- Xspecial symbols.
- X.B Cook
- Xis always case sensitive
- Xwhen reading cookbooks.
- X.P
- XThe characters
- X.B ":;={}[]"
- Xare the special symbols,
- Xand are words in themselves,
- Xneeding no delimiting.
- X.P
- XIn addition to the special symbols,
- Xsome words,
- Xknown as
- X.IR keywords ,
- Xhave special meaning to
- X.BR cook .
- XThe keywords are:
- X.TS
- Xcenter, tab(;);
- Xce ce ce ce.
- Xif;then;else;set
- Xloop;loopstop;fail;unsetenv
- X.TE
- XYou will meet the keywords in later sections.
- X.H 3 "Escape Sequences"
- XThe character
- X.B \e
- Xis the
- X.I escape
- Xcharacter.
- XIf a character is preceded by a
- X.B \e
- Xany specialness,
- Xif it had any,
- Xwill be removed.
- XIf it had no specialness it may have some added.
- X.P
- XThis means that,
- Xif you want to use
- X.B if
- Xas a word,
- Xrather than a keyword,
- Xat least one of its characters needs to be escaped,
- Xfor example
- X.BR \eif .
- X.P
- XThe escape sequences which are special are as follows.
- X.TS
- Xcenter, tab(;);
- Xcf(B) lw(2.2i).
- X\eb;The backspace character
- X\ef;The form feed character
- X\en;The newline or linefeed character
- X\er;The carriage return character
- X\et;The horizontal tab character
- X\e\fInnn\fP;T{
- XA character with a value of
- X.IR nnn ,
- Xwhere
- X.I nnn
- Xis an octal number of at most 3 digits.
- XT}
- X.TE
- XAn escaped end-of-line is totally ignored.
- XIt should be noted that a cookbook may not have any non-printing
- Xascii characters in it other than space, tab and end-of-line.
- X.H 3 "Quoting"
- XWords, and sections of words, may be quoted.
- XIf any part of a word is quoted it cannot be a keyword.
- X.P
- XThis means that,
- Xif you want to use
- X.B if
- Xas a word, rather than a keyword,
- Xat least one of its characters needs to be quoted,
- Xfor example
- X.BR "\&'if'" .
- X.P
- XBoth single
- X.RB ( ' )
- Xand double
- X.RB ( \\" )
- Xquotes are understood by
- X.BR cook ,
- Xand one may enclose the other.
- XIf a quote is escaped it does not open or close a quote as it usually
- Xwould.
- X.P
- X.B Cook
- Xdoes not like newlines within quotes.
- XThis is a generally good heuristic for catching unbalanced quotes.
- X.H 3 "Comments"
- XComments are delimited on the left by
- X.BR /* ,
- Xand on the right by
- X.BR */ ,
- XIf the
- X.B /
- Xcharacter has been escaped or quoted,
- Xit doesn't introduce a comment.
- XComments may be nested.
- XComments may span multiple lines.
- XComments are replaced by one logical space.
- X.SK
- X.H 2 "Preprocessor"
- XThe preprocessor may be thought of as doing a little work before the
- X.I "Syntax and Semantics"
- Xsection has its turn.
- X.P
- XThe preprocessor is driven by
- X.IR "preprocessor directives" .
- XA preprocessor directive is a line
- Xwhich starts with a hash
- X.RB ( # )
- Xcharacter.
- XEach of the preprocessor directives is described below.
- X.H 3 "include"
- XThe most common preprocessor directive is
- X.eB
- X#include "\f(CIfilename\fP"
- X.eE
- X.P
- XThis preprocessor directive is processed as if the contents
- Xof the named file had appeared in the cookbook,
- Xrather than the preprocessor include directive.
- X.P
- XThe most common use of the #include directive is to include
- Xsystem cookbooks.
- X.P
- XThe standard places to search are first any path specified with the
- X.B -Include
- Xcommand line option,
- Xand then
- X.I $HOME/.cook
- Xand
- Xthen
- X.IR /usr/local/lib/cook
- Xin that order.
- X.H 3 "if"
- XThe #if directive may be used to conditionally pass tokens to
- Xthe syntax and semantics processing.
- XDirectives take the form
- X.eB
- X#if \fIexpression1\fP
- X\fIsomething1\fP
- X#elif \fIexpression2\fP
- X\fIsomething2\fP
- X#else
- X\fIsomething3\fP
- X#endif
- X.eE
- XThere may be any number of \f(CWelif\fP clauses,
- Xand the \f(CWelse\fP
- Xclause is optional.
- XOnly one of the
- X.I somethings
- Xwill be passed through.
- X.H 3 "ifdef"
- XThis directive takes a similar form to the \f(CWif\fP directive,
- Xbut with a different first line:
- X.eB
- X#ifdef \fIvariable\fP
- X.eE
- XThis is syntactic sugar for
- X.eB
- X#if [defined \fIsymbol\fP]
- X.eE
- XThis is of most use in bracketing \f(CW#include\fP directives.
- X.H 3 "ifndef"
- XThis directive takes a similar form to the \f(CWif\fP directive,
- Xbut with a different first line:
- X.eB
- X#ifndef \fIvariable\fP
- X.eE
- XThis is syntactic sugar for
- X.eB
- X#if [not [defined \fIsymbol\fP]]
- X.eE
- XThis is of most use in bracketing \f(CW#include\fP directives.
- X.H 3 "pragma"
- XThis is for the addition of extensions.
- X.H 4 "once"
- XThis directive is to ensure that include files in which it appears are included exactly once.
- X.P
- XThis directive has the form
- X.eB
- X#pragma once
- X.eE
- X.H 4 "unknown extensions"
- XAny extensions not recognised will be ignored.
- X.SK
- X.H 2 "Syntax Descriptions"
- XIn the syntax descriptions which follow
- Xthere are several meta symbols,
- Xdefined as follows.
- X.TS
- Xcenter, tab(;);
- Xcf(B) lw(2.5i).
- X\&=;A definition symbol.
- X\&|;The alternative symbol.
- X\&.;The end-of-production symbol.
- X\&/*\fItext\fB*/;This is a comment.
- X\&'\fItext\fB';T{
- XThe
- X.I text
- Xis a literal terminal symbol of the grammar being defined.
- XT}
- X.TE
- X.P
- XLike all real languages,
- Xthe format is free form,
- Xno columns or end-of-line are significant.
- X.P
- XAs an example, the syntax description format is described using itself.
- X.eB
- Xsyntax
- X = /* empty */
- X | syntax production
- X .
- X.eE
- XA syntax definition may consist of zero or more productions.
- X.eB
- Xproduction
- X = name '\fB=\fP' term '\fB.\fP'
- X .
- X.eE
- XA production names a non-terminal symbol of the grammar being defined
- Xon the left,
- Xand its expansion on the right.
- X.eB
- Xterm
- X = factor
- X | term \fB'|'\fP term
- X .
- X.eE
- XA term may consist of a factor;
- Xor
- Xa term may consist of zero or more of the above terms
- Xseparated by
- X.I alternative
- Xsymbols.
- X.eB
- Xfactor
- X = /* empty */
- X | factor name
- X | factor literal
- X .
- X.eE
- XA factor consists of
- Xzero or more symbol names (terminal or non-terminal)
- Xor literals in a row.
- X.P
- XA symbol is terminal if it is not named on the left-hand-side of a production,
- Xor it is a literal.
- X.SK
- X.H 2 "Syntax and Semantics"
- X.H 3 "Overall Structure"
- XThe general form of the cookbook is defined as
- X.eB
- Xcookbook
- X = /* empty */
- X | cookbook statement
- X .
- X.eE
- XA cookbook is defined as a sequence of statements.
- XEach statement statement is executed.
- XFor a definition of what it means when a statement is executed,
- Xsee the individual statement definitions.
- X.P
- XThe nonterminal symbol
- X.I statement
- Xwill be defined in the sections below.
- X.P
- XPlease note that a statement is not always evaluated when is is read,
- Xbut at specific, well defined times.
- X.H 3 "The Compound Statement"
- XA nonterminal symbol which will be referred to below is the
- X.I compound_statement
- Xsymbol,
- Xdefined as follows:
- X.eB
- Xcompound_statement
- X = '\fB{\fP' statements '\fB}\fP'
- X .
- Xstatements
- X = /* empty */
- X | statements statement
- X .
- X.eE
- XThe compound statement may be used anywhere a statement may be,
- Xand in particular
- X.eB
- Xstatement
- X = compound_statement
- X .
- X.eE
- X.H 3 "Variables and Expressions"
- X.B Cook
- Xprovides variables to the user to simplify things.
- X.H 4 "The Assignment Statement"
- XIt is possible to assign to variables with the following statement.
- X.eB
- Xstatement
- X = expr '\fB=\fP' exprs '\fB;\fP'
- X .
- X.eE
- XWhen this statement is executed,
- Xthe variable whose name the left hand expression evaluates to will be
- Xassigned the value that the right hand expression list evaluates to.
- X.H 4 "Expressions"
- XMany definitions make reference to the
- X.IR expr,
- X.I elist
- Xand
- X.I exprs
- Xnonterminal symbols.
- XThese are defined as follows.
- X.P
- XThe
- X.I elist
- Xis a list of at least one expression,
- Xwhereas the
- X.I exprs
- Xis a list of zero or more expressions.
- X.eB
- Xelist
- X = expr
- X | elist expr
- X .
- Xexprs
- X = /* empty */
- X | exprs expr
- X .
- X.eE
- X.P
- XAn expression is composed of variable references,
- Xfunction invocations,
- Xwords,
- Xor concatenation of expressions.
- XThe concatenation is implied by abutting the two parts of the expression
- Xtogether,
- Xe.g.: "\f(CW[fred]>thing\fP" is an
- Xindirection on
- X.I fred
- Xconcatenated with the literal word "\f(CW>thing\fP".
- X.eB
- Xexpr
- X = WORD
- X | '\fB[\fP' elist '\fB]\fP'
- X | expr \fIcat\fP expr
- X .
- X.eE
- X.P
- XWhen an
- X.BI [ elist ]
- Xexpression is evaluated,
- Xthe
- X.I elist
- Xis evaluated first.
- XIf the result is a single word, then a variable of that name is
- Xsearched for.
- XIf found the value of an expression of this form is the value of the variable.
- X.P
- XIf there is no variable of the given name,
- Xor the
- X.I elist
- Xevaluated to more than one word,
- Xthe first word is taken to be a built-in function name.
- XIf there is no function of this name it is an error.
- X.P
- XThe
- X.I cat
- Xoperator works as one would expect,
- Xjoining the last word of the left
- Xexpression and the first word of the right expression together,
- Xand otherwise leaving the order of the expressions alone.
- XOne usually uses the trivial case of single word expressions.
- X.H 3 "Recipes"
- XA number of forms of
- X.I statement
- Xare concerned with telling
- X.B cook
- Xhow to cook things.
- XThere are three forms,
- Xthe
- X.I explicit
- Xrecipe,
- Xthe
- X.I implicit
- Xrecipe,
- Xand the
- X.I ingredients
- Xrecipe.
- X.H 4 "The Explicit Recipe Statement"
- XThe explicit recipe has the form
- X.eB
- Xstatement
- X = elist '\fB:\fP' exprs flags compound_statement
- X .
- X.eE
- XThe target(s) of the recipe are to the left of the colon,
- Xand the ingredients, if any, are to the right.
- XThe statements, usually commands, to perform to cook the target(s)
- Xare contained in the compound statement.
- XThe expressions are only evaluated into words when the recipe is
- Xinstanciated.
- X.P
- XThe \fIflags\fP are defined as follows.
- X.eB
- Xflags
- X = /* empty */
- X | '\fBset\fP' words
- X .
- X.eE
- XA number of flags may be used
- X.VL 1i
- X.LI errok
- XIf the errok flag is specified,
- Xthe commands within the actions bound to the recipe will always be successful.
- X.LI forced
- XIf the forced flag is specified,
- Xthe actions bound to the recipe will always be evaluated.
- X.LI precious
- XIf the precious flag is specified,
- Xif the actions bound to the recipe fail,
- Xthe targets of the recipe will not be deleted,
- Xas is the default.
- X.LI silent
- XIf the silent flag is specified,
- Xthe command within the actions bound to the recipe will not be echoed.
- X.LI wildpath
- XIf the wildpath flag is specified in an implicit recipe,
- Xleading path on pattern matches will be prepended to reconstructions.
- X.LI meter
- XIf the meter flag is specified,
- Xa summary of the CPU usage by the commands within this recipe
- Xwill be printed after each command.
- XThe silent options override this option.
- X.LI clearstat
- XThe date-time-modified of the files named in executed commands will be
- Xremoved from the time cache.
- XThis is essential for commands such as
- X.IR rm (1)
- Xand
- X.IR mv (1).
- X.LE
- X.H 4 "The Implicit Recipe Statement"
- XImplicit recipes are distinguished from explicit recipes in that
- Xand implicit recipe has a target with a '\fB%\fP' character in it.
- X.H 5 "Simple Form"
- X.P
- XIn general the user will rarely need to use the implicit recipe
- Xform, as there are a huge range of implicit recipes already
- Xdefined in the system default recipes.
- X.P
- XAn example of this recipe form is
- X.eB
- X%: %.Z
- X {
- X uncompress %;
- X }
- X.eE
- XThis recipe tells
- X.B cook
- Xhow to use the
- X.IR uncompress (1)
- Xprogram.
- X.H 5 "Complex Form"
- XThe implicit recipe recipe has a second form
- X.eB
- Xstatement
- X = elist '\fB:\fP' exprs1 '\fB:\fP' exprs2 flags compound_statement
- X .
- X.eE
- XIn this form,
- Xthe ingredients specified in
- X.I exprs1
- Xare used to determine the applicability of the recipe;
- Xif these are all constructable then the recipe will be applied,
- Xif any are not constructable then the recipe will not be applied.
- XIf the recipe is applied,
- Xthe ingredients specified in
- X.I exprs2
- Xare required to be constructable.
- XThe
- X.I exprs2
- Xsection is known as the
- X.I "forced ingredients"
- Xsection.
- X.P
- XAn example of this is the C recipe
- X.eB
- X%.o: %.c: [collect c_incl %.c]
- X {
- X cc -c %.c;
- X }
- X.eE
- XThis recipe is applied if the
- X.I %.c
- Xfile can be constructed,
- Xand is not applied if it cannot be constructed.
- XThe include dependencies are only expressed if the recipe
- Xis going to be applied;
- Xbut if they are expressed, they
- X.I must
- Xbe constructable.
- XThis means that absent include files generate an error.
- X.P
- XThe naive form of this recipe
- X.eB
- X%.o: %.c [collect c_incl %.c]
- X {
- X cc -c %.c;
- X }
- X.eE
- Xwill attempt to apply the
- X.I c_incl
- Xcommand before the
- X.I %.c
- Xfile is guaranteed to exist.
- XThis is because the
- X.I exprs2
- Xis performed after the
- X.I exprs1
- Xall exist (because they are constructable, they have been constructed).
- XIn this naive form,
- Xabsent include files result in the recipe not being applied.
- X.H 4 "The Ingredients Recipe Statement"
- XThe ingredients recipe has the form
- X.eB
- Xstatement
- X = elist '\fB:\fP' elist '\fB;\fP'
- X .
- X.eE
- XThe target(s) of the recipe are to the left of the colon,
- Xand the prerequisites are to the right.
- XThere are no statements to perform to cook the targets
- Xof this recipe, it is simply supplementary to any other recipe,
- Xusually an implicit recipe.
- X.P
- XThe expressions are only evaluated into words when the recipe is instanciated.
- X.H 3 "Commands"
- XCommands may take several forms in
- X.BR cook .
- XThey all have one thing in common; they execute a command.
- X.eB
- Xstatement
- X = command
- X .
- X.eE
- X.H 4 "The Simple Command Statement"
- XThe simplest command form is
- X.eB
- Xcommand
- X = simple_command
- X .
- Xsimple_command
- X = elist flags '\fB;\fP'
- X .
- X.eE
- XWhen executed,
- Xthe
- X.I elist
- Xis evaluated into a word list
- Xand used as a command to be passed to the operating system.
- XWhile this is usually sufficient,
- Xsome programs,
- Xnotably
- X.IR newgrp (1),
- Xrequire slightly more.
- X.H 4 "The Data Command Statement"
- XFor programs which require
- X.I stdin
- Xto be supplied by
- X.B cook
- Xto perform their functions,
- Xthe data command statement has been provided.
- X.eB
- Xcommand
- X = simple_command
- X '\fBdata\fP'
- X expr
- X '\fBdataend\fP'
- X .
- X.eE
- XIn this form,
- Xthe
- X.I expr
- Xis evaluated and used as input to the
- Xcommand.
- XBetween the
- X.B data
- Xand
- X.B dataend
- Xkeywords the definition of the special symbols and whitespace change.
- XThere are only two special symbols,
- X.B [
- Xand
- X.BR ] ,
- Xto allow functions and variable references to appear in the expression.
- XIn addition,
- Xwhitespace ceases to have its usual specialness;
- Xit is handed to the command,
- Xinstead.
- X.P
- XThe
- X.B data
- Xkeyword must be the last on a line,
- Xwhitespace after the
- X.B data
- Xkeyword up to and including end-of-line,
- Xwill
- X.I not
- Xbe given to the command.
- X.P
- XThe
- X.B dataend
- Xkeyword must appear alone on a line,
- Xoptionally surrounded by whitespace;
- Xit is is not alone,
- Xit is not a
- X.B dataend
- Xkeyword and will not terminate the expression.
- X.P
- XAn example of this may be useful.
- X.eB
- X/usr/fred/%: %
- X {
- X newgrp fred;
- X data
- X cp % /usr/fred/%
- X dataend
- X }
- X.eE
- XIf the directory
- X.I /usr/fred
- Xhas read-only permissions for others,
- Xand group write permissions,
- Xand belonged to group
- X.IR fred ,
- Xand you were a member of group
- X.IR fred ,
- Xthe above implicit recipe could be used to copy the file.
- X.H 4 "The Fail Statement"
- X.B Cook
- Xcan be forced to think that a recipe has failed
- Xby the uses of the
- X.B fail
- Xstatement.
- X.eB
- Xstatement
- X = '\fBfail\fP' '\fB;\fP'
- X .
- X.eE
- XThis is hugely useful when programs do not return a useful exit
- Xstatus,
- Xbut
- X.I do
- Xfail to produce the goods.
- X.P
- XAnother variation of this statement is
- X.eB
- Xstatement
- X = '\fBfail\fP' '\fBbacktrack\fP' '\fB;\fP'
- X .
- X.eE
- XThis enables you to write a recipe which will succeed if all of the ingredients are up-to-date,
- Xbut cause
- X.B cook
- Xto backtrack if any of the ingredients are out-of-date.
- XIt is useful with some software configuration management systems.
- X.H 3 "Flow Control"
- XThis section details statement forms which the casual user will never need.
- X.H 4 "The If Statement"
- XThe if statement has one of two forms.
- X.eB
- Xstatement
- X = '\fBif\fP' expr '\fBthen\fP' statement
- X | '\fBif\fP' expr '\fBthen\fP' statement '\fBelse\fP' statement
- X .
- X.eE
- XIn nested if statements,
- Xthe
- X.B else
- Xwill bind to the closest
- X.BR else -less
- X.BR if .
- X.P
- XAn expression is false if and only if all of its words are null or it
- Xhas no words.
- X.H 4 "The Loop and Loopend Statements"
- XLooping is provided for in
- X.B cook
- Xby the generic infinite loop construct defined below.
- XA facility is provided to break out of a loop at any point.
- X.eB
- Xstatement
- X = '\fBloop\fP' statement
- X | '\fBloopstop\fP' '\fB;\fP'
- X .
- X.eE
- XThe statement following the
- X.B loop
- Xdirective is executed repeatedly forever.
- XThe
- X.B loopstop
- Xstatement is only semantically valid within the scope of a
- X.B loop
- Xstatement.
- END_OF_FILE
- if test 18062 -ne `wc -c <'doc/language'`; then
- echo shar: \"'doc/language'\" unpacked with wrong size!
- fi
- # end of 'doc/language'
- fi
- echo shar: End of archive 8 \(of 11\).
- cp /dev/null ark8isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-